package com.dzl.integral.service.impl;

import com.dzl.base.service.BaseServiceImpl;
import com.dzl.config.database.Master;
import com.dzl.config.exception.CommonException;
import com.dzl.enterprise.pojo.WelfareEnterprise;
import com.dzl.enterprise.service.WelfareEnterpriseService;
import com.dzl.integral.dao.WelfareIntegralGrantMapper;
import com.dzl.integral.pojo.WelfareIntegralGrant;
import com.dzl.integral.pojo.WelfareIntegralGrantDetail;
import com.dzl.integral.pojo.WelfareIntegralGrantRecordRel;
import com.dzl.integral.pojo.dto.WelfareIntegralGrantDto;
import com.dzl.integral.pojo.query.WelfareIntegralGrantQuery;
import com.dzl.integral.pojo.query.WelfareIntegralRecordQuery;
import com.dzl.integral.pojo.vo.WelfareIntegralGrantVo;
import com.dzl.integral.pojo.vo.WelfareIntegralRecordVo;
import com.dzl.integral.service.WelfareIntegralGrantDetailService;
import com.dzl.integral.service.WelfareIntegralGrantRecordRelService;
import com.dzl.integral.service.WelfareIntegralGrantService;
import com.dzl.integral.service.WelfareIntegralRecordService;
import com.dzl.operation.pojo.WelfareOperationLog;
import com.dzl.operation.service.OperationLogService;
import com.dzl.userwx.pojo.WelfareUserOrganization;
import com.dzl.userwx.pojo.WelfareUserWx;
import com.dzl.userwx.pojo.dto.UserWxIntegralDto;
import com.dzl.userwx.service.WelfareUserOrganizationService;
import com.dzl.userwx.service.WelfareUserPurchasesNumService;
import com.dzl.userwx.service.WelfareUserWxService;
import com.dzl.util.EmptyUtils;
import com.dzl.util.RedisUtil;
import com.github.pagehelper.PageHelper;
import org.redisson.api.RLock;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 积分分发记录表(WelfareIntegralGrant)表服务实现类
 *
 * @author caobucao
 * @date 2021-09-07 10:39:32
 */
@Service
public class WelfareIntegralGrantServiceImpl extends BaseServiceImpl<WelfareIntegralGrant> implements WelfareIntegralGrantService {

    @Autowired
    private WelfareIntegralGrantMapper mapper;
    @Autowired
    private WelfareUserOrganizationService welfareUserOrganizationService;
    @Autowired
    private WelfareIntegralGrantDetailService welfareIntegralGrantDetailService;
    @Autowired
    private WelfareEnterpriseService welfareEnterpriseService;
    @Autowired
    private WelfareIntegralRecordService welfareIntegralRecordService;
    @Autowired
    private WelfareIntegralGrantRecordRelService welfareIntegralGrantRecordRelService;
    @Autowired
    private WelfareUserWxService welfareUserWxService;
    @Autowired
    private OperationLogService operationLogService;
    @Autowired
    private WelfareUserPurchasesNumService welfareUserPurchasesNumService;

    @Override
    public List<WelfareIntegralGrantVo> getIntegralGrantPage(WelfareIntegralGrantQuery query) {
        PageHelper.startPage(query);
        return mapper.selectIntegralGrantVo(query);
    }

    @Transactional(rollbackFor = Exception.class)
    @Master
    @Override
    public Integer saveIntegralGrant(WelfareIntegralGrantDto dto) {
        String key = "SAVE_INTEGRAL_GRANT"+dto.getEnterpriseId() + dto.getUpdater();
        RLock rLock = RedisUtil.lock(key);
        try {
            if (rLock.tryLock(15, TimeUnit.SECONDS)) {
                Date createTime = new Date();
                //先查积分余额够不够
                WelfareEnterprise welfareEnterprise = welfareEnterpriseService.selectByPrimaryKey(dto.getEnterpriseId());
                BigDecimal balanceIntegral = welfareEnterprise.getBalanceIntegral();
                //计算所需积分
                final BigDecimal needIntegral = dto.getIntegral().multiply(new BigDecimal(dto.getUserIdList().size()));
                if(needIntegral.compareTo(balanceIntegral) == 1) {
                    //如果所需积分大于积分余额
                    throw new CommonException("积分余额不足！");
                }
                //写入数据到积分分发表
                WelfareIntegralGrant grant = new WelfareIntegralGrant();
                grant.setName(dto.getName());
                grant.setGrantTime(dto.getGrantDateTime());
                grant.setAccountTime(dto.getAccountDateTime());
                grant.setExpireTime(dto.getExpireDateTime());
                grant.setGrantIntegral(needIntegral);
                grant.setGrantPeople(dto.getUserIdList().size());
                grant.setGrantState(1); //分发状态：1分发中，2已到账，3已终止
                grant.setCreater(dto.getCreater());
                grant.setUpdater(dto.getUpdater());
                grant.setEnterpriseId(dto.getEnterpriseId());
                mapper.insertSelective(grant);
                Integer grantId = grant.getId();
                //写入数据到积分分发与积分充值中间表
                //再查最近充值的一笔积分
                WelfareIntegralRecordQuery query = new WelfareIntegralRecordQuery();
                query.setEnterpriseId(dto.getEnterpriseId());
                query.setStatus(3); //状态：1 待审核 2 已审核 3已到账 4 已取消 5 已撤回
                List<WelfareIntegralRecordVo> integralRecordVoList = welfareIntegralRecordService.selectIntegralRecordNoGrantOrIsGrantButHasIntegralList(query);
                BigDecimal i = needIntegral; //会变的所需积分，循环里面用的
                for(WelfareIntegralRecordVo x : integralRecordVoList) {
                    Integer recordId = x.getId();
                    //查询这条充值记录的已分发总积分
                    BigDecimal totalGrantIntegral = welfareIntegralGrantRecordRelService.selectSumTotalGrantIntegral(recordId);
                    //计算出这条充值记录的剩余积分
                    BigDecimal surplusIntegral = x.getRechargeIntegral().subtract(totalGrantIntegral);
                    //判断剩余积分是否大于所需积分
                    WelfareIntegralGrantRecordRel welfareIntegralGrantRecordRel = new WelfareIntegralGrantRecordRel();
                    welfareIntegralGrantRecordRel.setGrantId(grantId);
                    welfareIntegralGrantRecordRel.setRecordId(recordId);
                    if(surplusIntegral.compareTo(i) > 0) {
                        //如果剩余积分大于所需积分
                        welfareIntegralGrantRecordRel.setGrantIntegral(i); //扣除所需积分
                        welfareIntegralGrantRecordRelService.insertSelective(welfareIntegralGrantRecordRel);
                        //充值完成，跳出循环
                        break;
                    } else {
                        //如果剩余积分小于所需积分
                        welfareIntegralGrantRecordRel.setGrantIntegral(surplusIntegral); //扣除当前充值记录的全部剩余积分
                        welfareIntegralGrantRecordRelService.insertSelective(welfareIntegralGrantRecordRel);
                        //i减去当前这笔分发的积分
                        i = i.subtract(surplusIntegral);
                        if(i.compareTo(BigDecimal.ZERO) == 0) {
                            //如果当下剩余要充值的钱变为0了，跳出循环
                            break;
                        }
                    }
                }
                //写入数据到积分分发详情表
                List<Integer> userIdList = dto.getUserIdList();
                List<WelfareIntegralGrantDetail> integralGrantDetailList = new ArrayList<>();
                userIdList.forEach(x -> {
                    //通过用户id查询用户的所属组织架构
                    //一个用户可能隶属于多个组织架构，取第一个
                    Example userOrganizationExample = new Example(WelfareUserOrganization.class);
                    userOrganizationExample.createCriteria().andEqualTo("userId", x);
                    List<WelfareUserOrganization> list = welfareUserOrganizationService.selectByExample(userOrganizationExample);
                    if(EmptyUtils.isEmpty(list)) {
                        throw new CommonException("选中人员中有人在程序运行时被开除！请重新选择！");
                    }
                    WelfareUserOrganization userOrganization = list.get(0);
                    Integer organizationId = userOrganization.getId();
                    WelfareIntegralGrantDetail integralGrantDetail = new WelfareIntegralGrantDetail();
                    integralGrantDetail.setGrantId(grantId);
                    integralGrantDetail.setOrganizationId(organizationId);
                    integralGrantDetail.setUserId(x);
                    integralGrantDetail.setGrantIntegral(dto.getIntegral());
                    integralGrantDetail.setType(1); //类型；1:分发，2:消费，3:过期
                    integralGrantDetail.setCreateTime(createTime);
                    integralGrantDetailList.add(integralGrantDetail);
                });
                welfareIntegralGrantDetailService.insertList(integralGrantDetailList);
                if(EmptyUtils.isNotEmpty(userIdList)){
                    //更新用户卡限制（购买）次数
                    welfareUserPurchasesNumService.updatePurchasesNumByUserIds(userIdList);
                }
                //给用户分发积分
//              welfareUserWxService.updateUserIntegral(dto.getUserIdList(), dto.getIntegral());
                //扣减企业积分余额
                welfareEnterprise.setBalanceIntegral(welfareEnterprise.getBalanceIntegral().subtract(needIntegral));
                welfareEnterprise.setConsumeIntegral(welfareEnterprise.getConsumeIntegral().add(needIntegral));
                return welfareEnterpriseService.updateByPrimaryKeySelective(welfareEnterprise);
            }
        } catch (Exception e) {
            throw new CommonException(e.getMessage());
        } finally {
            if (rLock.isHeldByCurrentThread()) {
                rLock.unlock();
            }
        }
        return null;
    }

    @Master
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer updateIntegralGrantState() {
        Integer count = 0;
        //查询所有需要到账的积分数据
        List<WelfareIntegralGrant> integralGrantList = mapper.selectNeedToAccount();
        if(EmptyUtils.isNotEmpty(integralGrantList)) {
            for(WelfareIntegralGrant x : integralGrantList) {
                //查询每条需要到账的积分与他关联的用户
                Integer grantId = x.getId();
                Example userOrganizationExample = new Example(WelfareIntegralGrantDetail.class);
                userOrganizationExample.createCriteria().andEqualTo("grantId", grantId).andEqualTo("type", 1);
                List<WelfareIntegralGrantDetail> integralGrantDetailList = welfareIntegralGrantDetailService.selectByExample(userOrganizationExample);
                if(EmptyUtils.isEmpty(integralGrantDetailList)) {
                    //程序出错，记录
                    WelfareOperationLog log = new WelfareOperationLog();
                    log.setRelationId(x.getId());
                    log.setContent("积分定时分发错误");
                    operationLogService.insertSelective(log);
                }
                BigDecimal integral = integralGrantDetailList.get(0).getGrantIntegral();
                List<Integer> organizationIds = integralGrantDetailList.stream().map(WelfareIntegralGrantDetail::getOrganizationId).collect(Collectors.toList());
                //查询关联用户
                List<Integer> userIds = welfareUserOrganizationService.selectUserIdListByIds(organizationIds);
                if(EmptyUtils.isEmpty(userIds)) {
                    //程序出错，记录
                    WelfareOperationLog log = new WelfareOperationLog();
                    log.setRelationId(x.getId());
                    log.setContent("应该是数据库组织架构和用户表被清理，也可能是员工被开除了");
                    operationLogService.insertSelective(log);
                }
                //userIds去重
//                        List<Integer> distinctUserIds = userIds.stream().distinct().collect(Collectors.toList());
                if(CollectionUtils.isEmpty(userIds)) {
                    continue;
                }
                //更改用户表里面的积分信息
                Integer co = welfareUserWxService.updateUserIntegral(userIds, integral);
                //更改用户虚拟商品购买次数信息表的数据
                //Integer co2 =
                //
                count += co;
                //分发完成后给改积分记录设置为已到账
                WelfareIntegralGrant welfareIntegralGrant = new WelfareIntegralGrant();
                welfareIntegralGrant.setId(grantId);
                welfareIntegralGrant.setGrantState(2); //分发状态：1分发中，2已到账，3已终止
                mapper.updateByPrimaryKeySelective(welfareIntegralGrant);
            }
            return count;
        }
        return 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Master
    @Override
    public Integer updateIntegralExpiredState() {
        int count = 0;
        //查出所有过期的分发记录
        List<WelfareIntegralGrant> integralGrantList = mapper.selectNeedToExpired();
        if(EmptyUtils.isNotEmpty(integralGrantList)) {
            for (WelfareIntegralGrant x : integralGrantList) {
                //查询需要过期的积分
                Integer grantId = x.getId();
                Example userOrganizationExample = new Example(WelfareIntegralGrantDetail.class);
                userOrganizationExample.createCriteria().andEqualTo("grantId", grantId);
                List<WelfareIntegralGrantDetail> expiredList = new ArrayList<>();
                List<UserWxIntegralDto> dtoList = new ArrayList<>();
                List<WelfareIntegralGrantDetail> integralGrantDetailList = welfareIntegralGrantDetailService.selectByExample(userOrganizationExample);
                if(EmptyUtils.isEmpty(integralGrantDetailList)) {
                    throw new CommonException("没有积分详情记录！");
                }
                for(WelfareIntegralGrantDetail y : integralGrantDetailList) {
                    Integer organizationId = y.getOrganizationId();
                    WelfareUserOrganization welfareUserOrganization = welfareUserOrganizationService.selectByPrimaryKey(organizationId);
                    Integer userId = welfareUserOrganization.getUserId();

                    //给用户扣除积分
                    UserWxIntegralDto dto = new UserWxIntegralDto();
                    dto.setId(userId);
//                    dtoList.add(dto);
                    //查询用户剩余积分
                    WelfareUserWx welfareUserWx = welfareUserWxService.selectByPrimaryKey(userId);
                    BigDecimal oldBalanceIntegral = welfareUserWx.getBalanceIntegral();
                    if(oldBalanceIntegral.compareTo(y.getGrantIntegral()) >= 0) {
                        //如果积分够扣，就扣那么多积分
                        dto.setIntegral(y.getGrantIntegral());
                    } else {
                        //否则，扣除全部剩余积分
                        dto.setIntegral(oldBalanceIntegral);
                    }
                    //给用户扣除积分
                    welfareUserWxService.updateIntegralForExpired(dto);

                    //积分详情表写入的扣除积分的对象
                    WelfareIntegralGrantDetail welfareIntegralGrantDetail = new WelfareIntegralGrantDetail();
                    welfareIntegralGrantDetail.setGrantId(grantId);
                    welfareIntegralGrantDetail.setGrantIntegral(dto.getIntegral());
                    welfareIntegralGrantDetail.setType(3); //类型；1:分发，2:消费，3:过期
                    welfareIntegralGrantDetail.setOrganizationId(y.getOrganizationId());
                    welfareIntegralGrantDetail.setUserId(userId);
                    expiredList.add(welfareIntegralGrantDetail);

                }
                //将积分分发表中该条分发记录更改为已过期
                WelfareIntegralGrant welfareIntegralGrant = new WelfareIntegralGrant();
                BeanUtils.copyProperties(x, welfareIntegralGrant);
                welfareIntegralGrant.setGrantState(4); //设置为已到期
                mapper.updateByPrimaryKeySelective(welfareIntegralGrant);
                //积分详情表插入过期数据
                int c = welfareIntegralGrantDetailService.insertList(expiredList);
                count += c;
            }
            return count;
        }
        return 0;
    }

    @Master
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BigDecimal updateGrantToStop(WelfareIntegralGrant welfareIntegralGrant) {
        WelfareIntegralGrant newGrant = mapper.selectByPrimaryKey(welfareIntegralGrant.getId());
        //判断积分状态
        if(!newGrant.getGrantState().equals(1)) {
            throw new CommonException("积分状态不是发放中，无法终止");
        }
        //将积分还给企业
        BigDecimal returnIntegral = newGrant.getGrantIntegral();
        Integer enterpriseId = welfareIntegralGrant.getEnterpriseId();
        WelfareEnterprise welfareEnterprise = welfareEnterpriseService.selectByPrimaryKey(enterpriseId);
        welfareEnterprise.setId(enterpriseId);
        welfareEnterprise.setBalanceIntegral(welfareEnterprise.getBalanceIntegral().add(returnIntegral)); //加积分余额
        welfareEnterprise.setConsumeIntegral(welfareEnterprise.getConsumeIntegral().subtract(returnIntegral)); //减已用积分
        welfareEnterpriseService.updateByPrimaryKeySelective(welfareEnterprise);
        //更新积分状态为已终止
        mapper.updateByPrimaryKeySelective(welfareIntegralGrant);
        return returnIntegral;
    }
}
